﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using BeautyTech.Core.Data;
using BeautyTech.Core.Domain.Catalogs;

namespace BeautyTech.Services.Catalogs
{
    public class ProductService : IProductService
    {
        #region fields

            private readonly IRepository<Product> _productRepository;
            private readonly IRepository<RelatedProduct> _relatedProductRepository;

        #endregion

        #region Constructor

            /// <summary>
            /// Ctor
            /// </summary>
            /// <param name="productRepository">Product repository</param>
            /// <param name="relatedProductRepository">Related product repository</param>
            public ProductService(IRepository<Product> products,
                                  IRepository<RelatedProduct> relatedProductRepository)
            {
                this._productRepository = products;
                this._relatedProductRepository = relatedProductRepository;
            }

        #endregion

        /// <summary>
        /// Gets product by Id
        /// </summary>
        /// <param name="productId">Product identifier</param>
        /// <returns>Product</returns>
        public Product GetProductById(int productId)
        {
            if (productId == 0)
                return null;

            return _productRepository.GetById(productId);
        }

        /// <summary>
        /// Get products by identifiers
        /// </summary>
        /// <param name="productIds">Product identifiers</param>
        /// <returns>Products</returns>
        public IList<Product> GetProductsByIds(int[] productIds)
        {
            if (productIds == null || productIds.Length == 0)
                return new List<Product>();

            var query = from p in _productRepository.Table
                        where productIds.Contains(p.Id)
                        select p;
            var products = query.ToList();
            //sort by passed identifiers
            var sortedProducts = new List<Product>();
            foreach (int id in productIds)
            {
                var product = products.Find(x => x.Id == id);
                if (product != null)
                    sortedProducts.Add(product);
            }
            return sortedProducts;
        }

        /// <summary>
        /// Gets product by Reference
        /// </summary>
        /// <param name="reference">Product Reference</param>
        /// <returns>Product</returns>
        public Product GetProductByReference(string reference)
        {
            if (String.IsNullOrEmpty(reference))
                return null;

            var query = from p in _productRepository.Table
                        where p.Reference == reference
                        select p;
            var product = query.FirstOrDefault();

            return product;
        }

        #region Related products

            /// <summary>
            /// Deletes a related product
            /// </summary>
            /// <param name="relatedProduct">Related product</param>
            public void DeleteRelatedProduct(RelatedProduct relatedProduct)
            {
                if (relatedProduct == null)
                    throw new ArgumentNullException("relatedProduct");

                _relatedProductRepository.Delete(relatedProduct);

            }

            /// <summary>
            /// Gets a related product collection by product identifier
            /// </summary>
            /// <param name="productId1">The first product identifier</param>
            /// <param name="showHidden">A value indicating whether to show hidden records</param>
            /// <returns>Related product collection</returns>
            public IList<RelatedProduct> GetRelatedProductsByProductId1(int productId1, bool showHidden = false)
            {
                var query = from rp in _relatedProductRepository.Table
                            join p in _productRepository.Table on rp.ProductId2 equals p.Id
                            where rp.ProductId1 == productId1 &&
                            (showHidden || p.Published)
                            orderby rp.DisplayOrder
                            select rp;
                var relatedProducts = query.ToList();

                return relatedProducts;
            }

            /// <summary>
            /// Gets a related product
            /// </summary>
            /// <param name="relatedProductId">Related product identifier</param>
            /// <returns>Related product</returns>
            public RelatedProduct GetRelatedProductById(int relatedProductId)
            {
                if (relatedProductId == 0)
                    return null;

                return _relatedProductRepository.GetById(relatedProductId);
            }

            /// <summary>
            /// Inserts a related product
            /// </summary>
            /// <param name="relatedProduct">Related product</param>
            public void InsertRelatedProduct(RelatedProduct relatedProduct)
            {
                if (relatedProduct == null)
                    throw new ArgumentNullException("relatedProduct");

                _relatedProductRepository.Insert(relatedProduct);

            }

            /// <summary>
            /// Updates a related product
            /// </summary>
            /// <param name="relatedProduct">Related product</param>
            public void UpdateRelatedProduct(RelatedProduct relatedProduct)
            {
                if (relatedProduct == null)
                    throw new ArgumentNullException("relatedProduct");

                _relatedProductRepository.Update(relatedProduct);

            }

        #endregion

    }
}
